package tests;

import static org.junit.Assert.*;

import java.util.List;

import model.filemanager.FileManager;
import model.filemanager.MediaFile;

import org.junit.*;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;

public class FileManagerTest {
	FileManager fm;
	BlobKey key;
	String user;
	String name;
	String type;
	long size;

	String searchType = null;
	String searchGenre = null;
	String searchParam = "name";	
	String searchQuery = null;
	String sortParam = "name" ;	
	boolean descending = true;
	int offSet = 0;
	int count = 50;
	Integer[] totalCount = new Integer[1];	
	
	
	@Before
	public void createFile() throws EntityNotFoundException {
        helper.setUp();		
        fm = new FileManager("atestname");
		key = new BlobKey("testKey");
		user = new String("testUser");
		name = new String("testName");
		type = new String("testType");
		size = 100000;
	}	

	@After
	public void tearDown() {
		helper.tearDown();
	}	

	private void createNewFile(String fileKey, String fileName, String fileType) throws EntityNotFoundException {
		BlobKey key;
		String user;
		String name;
		String type;
		long size;		
		key = new BlobKey(fileKey);
		user = new String("testUser");
		name = new String(fileName);
		type = new String(fileType);
		size = 100000;
		fm.SaveFile(key, name, type, size);
	}	
	@Test
	public void testConstructor() {
		fm = new FileManager("atestname");
		assertTrue("File Manager not initialised", fm instanceof FileManager);
	}
	
	@Test
	public void testSaveFile() {
		fm.SaveFile(key, name, type, size);
	}
	
	@Test
	public void testSaveTwoDifferentFiles() {
		BlobKey key2 = new BlobKey("anotherKey");
		String user2 = new String("anotherUser");
		String name2 = new String("anotherName");
		String type2 = new String("anotherType");
		fm.SaveFile(key, name, type, size);
		fm.SaveFile(key2, name2, type2, size);
	}
	
	@Test (expected=RuntimeException.class)
	public void testSaveSameFileTwice() {
		fm.SaveFile(key, name, type, size);
		fm.SaveFile(key, name, type, size);
	}
		
	@Test
	public void testGetExistingFile() throws EntityNotFoundException {
		testSaveFile();
		MediaFile file = fm.GetFile(key.getKeyString());
		assertTrue("Returned object not MediaFile", file instanceof MediaFile);
		assertEquals(name, file.getName());
		assertEquals(type, file.getType());
	}
	
	@Test (expected=EntityNotFoundException.class)
	public void testGetFileNotExisted() throws EntityNotFoundException {
		MediaFile file = fm.GetFile("Non-existant key");
	}
	
	@Test
	public void testGetAFileTwice() throws EntityNotFoundException {
		testSaveFile();
		MediaFile file1 = fm.GetFile(key.getKeyString());
		MediaFile file2 = fm.GetFile(key.getKeyString());
		assertEquals("Getting a file twice must return the same file", file1.getName(), file2.getName());		
	}
	
	@Test
	public void testGetTwoFiles() throws EntityNotFoundException {
		testSaveTwoDifferentFiles();
		MediaFile file1 = fm.GetFile("testKey");
		MediaFile file2 = fm.GetFile("anotherKey");	
		assertEquals(file1.getName(),"testName");
		assertEquals(file2.getName(),"anotherName");
	}
	
	@Test
	public void testUpdateFile() throws EntityNotFoundException {
		fm.SaveFile(key, name, type, size);
		MediaFile file = fm.GetFile(key.getKeyString());
		fm.UpdateFile(file);		
	}
	
	@Test (expected = Exception.class)
	public void testUpdateNullFile() {
		fm.UpdateFile(null);
	}
	
	
	@Test (expected=EntityNotFoundException.class)
	public void testDeleteFile() throws EntityNotFoundException {
		testSaveTwoDifferentFiles();
		
		assertEquals(fm.SearchForFiles(null, null, null, null, -1, false, 0, 10, totalCount).size(), 2);
		
		//Delete the file and assert the change in file size
		fm.DeleteFile("testKey");
		assertEquals(fm.SearchForFiles(null, null, null, null, -1, false, 0, 10, totalCount).size(), 1);
		
		//Grabbing the deleted file should throw an exception
		fm.GetFile("testKey");
	}
	
	
	@Test
	public void testDeleteNoneExistedFile() {
		// File "something" does not exist but we don't care
		fm.DeleteFile("something");	
	}
	
	@Test
	public void testSearchForImageByNameWithDefaultParameter() throws EntityNotFoundException {
		String fileName = "testImageName";		
		// Create a new image and add it into File Manager
		createNewFile("firstKey",fileName,"image");
		searchType = "image";
		searchQuery = "testImageName";
		List<MediaFile> listFile = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		// The result should contain one file
		assertEquals(listFile.size(), 1);
		// Take out the file
		MediaFile testFile = listFile.get(0);
		// The file must be an image
		assertEquals(testFile.getType(), "image");
		// The file must have correct name
		assertEquals(testFile.getName(), "testImageName");			
	}

	@Test
	public void testSearchForImageByNameSortedAscendingly() throws EntityNotFoundException {
		searchType = "image";
		searchQuery = null;
		createNewFile("firstKey","ZFile","image");
		createNewFile("secondKey","YFile","image");
		createNewFile("thirdKey","XFile","image");	
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, "name", -1, false, offSet, count, totalCount);
		assertEquals(listNewFiles.get(0).getName(),"XFile");
		assertEquals(listNewFiles.get(1).getName(),"YFile");
		assertEquals(listNewFiles.get(2).getName(),"ZFile");
	}

	@Test
	public void testSearchForImageByNameSortedDescendingly() throws EntityNotFoundException {
		searchType = "image";
		searchQuery = null;
		createNewFile("firstKey","AFile","image");
		createNewFile("secondKey","BFile","image");
		createNewFile("thirdKey","CFile","image");	
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, "name", -1, true, offSet, count, totalCount);
		assertEquals(listNewFiles.get(0).getName(),"CFile");
		assertEquals(listNewFiles.get(1).getName(),"BFile");
		assertEquals(listNewFiles.get(2).getName(),"AFile");
	}
	
	@Test
	public void testSearchForImagesByNameWithNoParameter() throws EntityNotFoundException {
		searchType = "image";
		searchQuery = null;
		List<MediaFile> listOldFiles = fm.SearchForFiles(searchType, searchParam, 
				searchQuery, sortParam, -1, descending, offSet, count, totalCount);
				
		createNewFile("firstKey","firstFile","image");
		createNewFile("secondKey","secondFile","image");
		createNewFile("thirdKey","thirdFile","image");
		// Search query is empty so the expected result should be all files		
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		// The result should contain three more new files
		assertEquals(listNewFiles.size() - listOldFiles.size(), 3);
	}	
	
	@Test
	public void testSearchForImagesByPartlyName() throws EntityNotFoundException {
		searchType = "image";
		searchParam = "name";
		searchQuery = "File";			
		createNewFile("firstKey","firstFile","image");
		createNewFile("secondKey","secondFile","image");
		createNewFile("thirdKey","thirdFile","image");	
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		assertEquals(listNewFiles.size(), 3);		
	}
	
	@Test
	public void testSearchForImagesByNameDifferentCase() throws EntityNotFoundException {
		searchType = "image";
		searchParam = "name";
		searchQuery = "firstfile";			
		createNewFile("firstKey","firstFile","image");		
		createNewFile("secondKey","FIRSTFILE","image");
		createNewFile("thirdKey","FIRSTfile","image");	
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		assertEquals(listNewFiles.size(), 3);		
	}

	@Test
	public void testSearchForImagesByPartlyNameDifferentCase() throws EntityNotFoundException {
		searchType = "image";
		searchParam = "name";
		searchQuery = "file";			
		createNewFile("firstKey","firstFile","image");
		createNewFile("secondKey","secondFile","image");
		createNewFile("thirdKey","thirdFile","image");	
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		assertEquals(listNewFiles.size(), 3);		
	}
	
	@Test
	public void testSearchForImagesByWrongName() throws EntityNotFoundException {
		searchType = "image";
		searchParam = "name";
		searchQuery = "something";			
		createNewFile("firstKey","firstFile","image");		
		createNewFile("secondKey","FIRSTFILE","image");
		createNewFile("thirdKey","FIRSTfile","image");	
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		assertEquals(listNewFiles.size(), 0);		
	}
	
	@Test
	public void testSearchForImageThatNotExist() throws EntityNotFoundException {
		searchType = "image";
		searchQuery = "something";
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
				searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		// The result should contain nothing
		assertEquals(listNewFiles.size(),0);
	}	
	
	@Test
	public void testSearchForAudioWithDefaultParamenter() throws EntityNotFoundException {
		String fileName = "testAudioName";
		// Create a new audio and add it into File Manager
		createNewFile("firstKey",fileName,"audio");
		
		searchType = "audio";
		searchQuery = new String(fileName);
		List<MediaFile> listFile = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		// The result should contain one file
		assertEquals(listFile.size(), 1);
		// Take out the file
		MediaFile testFile = listFile.get(0);
		// The file must be an audio
		assertEquals(testFile.getType(), "audio");
		// The file must have correct name
		assertEquals(testFile.getName(), "testAudioName");			
	}	
	
	@Test
	public void testSearchForMovieWithDefaultParamenter() throws EntityNotFoundException {
		String fileName = "testMovieName";
		// Create a new movie and add it into File Manager
		createNewFile("firstKey",fileName,"movie");
		
		searchType = "movie";
		searchQuery = new String(fileName);
		List<MediaFile> listFile = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);
		// The result should contain one file
		assertEquals(listFile.size(), 1);
		// Take out the file
		MediaFile testFile = listFile.get(0);
		// The file must be a movie
		assertEquals(testFile.getType(), "movie");
		// The file must have correct name
		assertEquals(testFile.getName(), "testMovieName");			
	}	
	
	@Test
	public void testSearchForFilesWithDifferentCount() throws EntityNotFoundException {
		searchType = "image";
		searchQuery = null;
		count = 2;
				
		createNewFile("firstKey","firstFile","image");
		createNewFile("secondKey","secondFile","image");
		createNewFile("thirdKey","thirdFile","image");
		// The count is set to 2 so there will be only two files in the result		
		List<MediaFile> listNewFiles = fm.SearchForFiles(searchType, searchParam, 
									searchQuery, sortParam, -1, descending, offSet, count, totalCount);		
		assertEquals(listNewFiles.size(), 2);		
	}
	
	private final LocalServiceTestHelper helper =
	            new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());	   
	
}
